#pragma once
#include "bObject.h"
#include<exception>
#include <ostream>

class NullReference:public std::exception,bObject
{
public:
	const char* what() const
	{
		return "Attempt to de-refer a null-reference.";
	}
};

template<class T=bObject>
class bReference
{
private:
	T* _obj;
public:
	bReference(void):_obj(nullptr){}

	bReference(T* ptr):_obj(nullptr)
	{
		operator=(ptr);
	}

	bReference(const bReference<T>& o):_obj(nullptr)
	{
		operator=(o);
	}

	bReference& operator=(const bReference<T>& o)
	{
		return operator=(o._obj);
	}

	T* object() const{
		if(_obj)
			return _obj;
		throw NullReference();
	}

	T* operator ->() const{return object();}

	operator T* () const { return object(); }

	bReference& operator=(T* ptr)
	{
		if(_obj)
			if(_obj->derefer())
				delete _obj;
		_obj=ptr;
		if(_obj)
			_obj->refer();
		return *this;
	}

	~bReference(void){
		bObject*p=_obj;
		operator=(nullptr);
	}
};

template<class bT>
std::ostream& operator << ( std::ostream& out, const bReference<bT>& ref)
{
	out << "[ Reference<" << typeid(bT).name () << "> points to 0x" << std::hex << ((unsigned long int)ref.object()) << "]";
	return out;
}